package com.lbj.mall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.lbj.mall.cart.entity.to.UserInfoTo;
import com.lbj.mall.cart.entity.vo.CartItemVo;
import com.lbj.mall.cart.entity.vo.CartVo;
import com.lbj.mall.cart.exception.CartException;
import com.lbj.mall.cart.feign.ProductFeign;
import com.lbj.mall.cart.interceptor.CartInterceptor;
import com.lbj.mall.cart.service.CartService;
import com.lbj.mall.common.entity.vo.SkuInfoVo;
import com.lbj.mall.common.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private StringRedisTemplate redis;
    @Autowired
    private ProductFeign productFeign;
    @Autowired
    private ThreadPoolExecutor executor;

    private static final String CART_PREFIX = "mall:cart:";

    @Override
    public CartItemVo addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        BoundHashOperations<String, Object, Object> operation = operation();
        String json = (String) operation.get(skuId.toString());
        if (json == null) {
            // 购物车中没有当前商品：添加商品
            CartItemVo item = new CartItemVo();
            // 1.根据skuId来从远程服务mall-product中查询商品信息
            CompletableFuture<Void> infoFuture = CompletableFuture.runAsync(() -> {
                R infoR = productFeign.info(skuId);
                SkuInfoVo skuInfoVo = JSON.parseObject(JSON.toJSONString(infoR.get("skuInfo")), new TypeReference<>() {
                });
                item.setCheck(true);
                item.setCount(num);
                item.setImage(skuInfoVo.getSkuDefaultImg());
                item.setPrice(skuInfoVo.getPrice());
                item.setTitle(skuInfoVo.getSkuTitle());
                item.setSkuId(skuId);
            }, executor);

            // 2.远程服务查询商品属性
            CompletableFuture<Void> attrFuture = CompletableFuture.runAsync(() -> {
                R attrR = productFeign.getAttrBySkuId(skuId);
                List<String> attrList = JSON.parseObject(JSON.toJSONString(attrR.get("data")), new TypeReference<>() {
                });
                item.setSkuAttrValues(attrList);
            }, executor);
            // 不要忘了调用get()方法
            CompletableFuture.allOf(infoFuture, attrFuture).get();

            // 将购物车数据转换成JSON格式保存到Redis中
            operation().put(skuId.toString(), JSON.toJSONString(item));
            return item;
        } else {
            // 购物车中有当前商品：添加数量即可
            CartItemVo cartItemVo = JSON.parseObject(json, CartItemVo.class);
            cartItemVo.setCount(cartItemVo.getCount() + num);
            operation.put(skuId.toString(), JSON.toJSONString(cartItemVo));
            return cartItemVo;
        }
    }

    @Override
    public CartItemVo getCardItem(Long skuId) {
        String json = (String) operation().get(skuId.toString());
        return JSON.parseObject(json, CartItemVo.class);
    }

    @Override
    public CartVo getCart() throws ExecutionException, InterruptedException {
        CartVo vo = new CartVo();
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        String tempCartKey = CART_PREFIX + userInfoTo.getUserKey();
        getCartItemList(tempCartKey);
        if (userInfoTo.getUserId() == null) {
            // 用户没有登录，展示临时购物车数据
            List<CartItemVo> cartItemList = getCartItemList(tempCartKey);
            vo.setItems(cartItemList);
        } else {
            // 用户已经登录，将临时购物车数据与登录后的购物车数据和并，再获取合并后的数据
            String userCartKey = CART_PREFIX + userInfoTo.getUserId();
            List<CartItemVo> cartItemList = getCartItemList(tempCartKey);
            if (cartItemList != null) {
                for (CartItemVo item : cartItemList) {
                    addToCart(item.getSkuId(), item.getCount());
                }
                // 将临时购物车数据和用户购物车数据合并之后，清空临时购物车数据
                clearCart(tempCartKey);
            }
            List<CartItemVo> userCardItemList = getCartItemList(userCartKey);
            vo.setItems(userCardItemList);
        }
        return vo;
    }

    @Override
    public void clearCart(String cartKey) {
        redis.delete(cartKey);
    }

    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> operation = operation();
        operation.delete(skuId.toString());
    }

    @Override
    public void checkItemNum(Long skuId, Integer num) {
        CartItemVo cardItem = getCardItem(skuId);
        cardItem.setCount(num);
        String json = JSON.toJSONString(cardItem);
        operation().put(skuId.toString(), json);
    }

    @Override
    public void checkItemSelect(Long skuId, Boolean checked) {
        CartItemVo cardItem = getCardItem(skuId);
        cardItem.setCheck(checked);
        String json = JSON.toJSONString(cardItem);
        operation().put(skuId.toString(), json);
    }

    private BoundHashOperations<String, Object, Object> operation() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        String userKey;
        if (userInfoTo.getUserId() != null) {
            // 用户登录过，获取UserId作为存储的key
            userKey = userInfoTo.getUserId() + "";
        } else {
            // 用户未登录过，使用UserKey作为存储的key
            userKey = userInfoTo.getUserKey();
        }
        // 这里存储购物车的数据使用的数据结构为：List<String k1,Map<String k2,Object>>
        // k1:redis中存储的key   k2:商品id，这个是为了方便修改某一条数据，否则用List的话修改一条数据就需要遍历了
        // 一般我们使用下面方法进行操作，但是因为每次都需要获取，RedisTemplate提供了更简便的方式
        // redis.opsForHash().get("","")
        return redis.boundHashOps(CART_PREFIX + userKey);
    }

    /**
     * 获取所有购物车数据项
     */
    private List<CartItemVo> getCartItemList(String cartKey) {
        // 获取购物车数据中保存的所有数据
        List<Object> values = redis.boundHashOps(cartKey).values();
        if (values != null) {
            return values.stream().map(item -> {
                String json = (String) item;
                return JSON.parseObject(json, CartItemVo.class);
            }).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public List<CartItemVo> getUserCartItems() {

        List<CartItemVo> cartItemVoList = new ArrayList<>();
        //获取当前用户登录的信息
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        //如果用户未登录直接返回null
        if (userInfoTo.getUserId() == null) {
            return null;
        } else {
            //获取购物车项
            String cartKey = CART_PREFIX + userInfoTo.getUserId();
            //获取所有的
            List<CartItemVo> cartItems = getCartItemList(cartKey);
            if (cartItems == null) {
                throw new CartException();
            }
            //筛选出选中的
            cartItemVoList = cartItems.stream()
                    .filter(CartItemVo::getCheck)
                    .peek(item -> {
                        //更新为最新的价格（查询数据库）
                        BigDecimal price = productFeign.getPrice(item.getSkuId());
                        item.setPrice(price);
                    })
                    .collect(Collectors.toList());
        }

        return cartItemVoList;
    }
}
